package com.hyq.learn.web.exception.handler;

import com.hyq.learn.common.exception.SvcException;
import com.hyq.learn.common.exception.errorcode.CommonErrorCode;
import com.hyq.learn.common.response.CommonResponse;
import jakarta.servlet.RequestDispatcher;
import jakarta.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.context.request.NativeWebRequest;


import java.util.Optional;

import static org.springframework.web.context.request.RequestAttributes.SCOPE_REQUEST;

public interface AdviceTrait {

    Logger LOGGER = LoggerFactory.getLogger(AdviceTrait.class);

    default <T> ResponseEntity<CommonResponse<T>> create(Throwable ex, final NativeWebRequest request, boolean isInternalRequest) {
        HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.class);
        String url = getRequestUrl(nativeRequest);
        LOGGER.error("Internal Server Error, url:{}, {}, error_msg:{}", nativeRequest.getMethod(), url, ex.getMessage(), ex);
        request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ex, SCOPE_REQUEST);
        CommonResponse<T> response;
        if (isInternalRequest) {
            response = CommonResponse.failure(CommonErrorCode.UNKNOWN_ERROR.getCode(), ex.getMessage());
        } else {
            response = CommonResponse.failure(CommonErrorCode.UNKNOWN_ERROR);
        }
        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(MediaType.APPLICATION_JSON)
                .header("Result-type", "exception")
                .header("X-http-status", String.valueOf(HttpStatus.INTERNAL_SERVER_ERROR.value()))
                .body(response);
    }

    default <T> ResponseEntity<CommonResponse<T>> create(SvcException ex, final NativeWebRequest request) {
        HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.class);
        String url = getRequestUrl(nativeRequest);
        Integer httpStatusCode = Optional.ofNullable(ex.getErrorCode().getHttpStatus()).orElse(HttpStatus.INTERNAL_SERVER_ERROR.value());
        String errorMsg = ex.getErrorCode().getCode() + "," + ex.getMessage();
        LOGGER.error("caught exception, status:{}, url:{}, {}, error_msg:{}", httpStatusCode, nativeRequest.getMethod(), url, errorMsg);
        if (httpStatusCode == HttpStatus.INTERNAL_SERVER_ERROR.value()) {
            request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, ex, SCOPE_REQUEST);
        }

        CommonResponse<T> response = CommonResponse.failure(ex.getErrorCode().getCode(), ex.getMessage());
        return ResponseEntity.status(httpStatusCode).contentType(MediaType.APPLICATION_JSON)
                .header("Result-type", "exception")
                .header("X-http-status", String.valueOf(httpStatusCode))
                .body(response);
    }

    default String getRequestUrl(HttpServletRequest nativeRequest) {
        return Optional.ofNullable(nativeRequest)
                .map(HttpServletRequest::getQueryString)
                .map(queryString -> nativeRequest.getRequestURI() + "?" + queryString)
                .orElse(Optional.ofNullable(nativeRequest).map(HttpServletRequest::getRequestURI).orElse(StringUtils.EMPTY));
    }

}
